package com.alstudio.utils.android.media.audio.player;

import android.content.Context;
import android.media.MediaPlayer;
import android.media.MediaPlayer.OnCompletionListener;
import android.media.MediaPlayer.OnPreparedListener;
import android.net.Uri;
import android.os.Handler;

/**
 * ALMusicPlayer实现音频播放功能，通過不同的構造方法可實現對Uri、/raw目錄下的資源文件、指定SD卡路徑的音頻文件進行播放。
 * 通過對應的API可執行播放、暫停、停止、設定循環播放、獲取音頻文件時長(毫秒)、獲取音頻文件絕對路徑等功能。 通過回調方法可得到播放狀態以及播放進度
 * 
 * @author Alonso Lee
 * 
 */
public class ALMusicPlayer implements ALMusicPlayerEngine {

	private final int UPDATE_MUSIC_TIME_PERIOD = 1000;

	public boolean isPreparing = false;
	private MediaPlayer mPlayer;
	private ALMusicPlayerCallback mCallback;
	private Context mContext;
	private String mPath;
	private int resId;
	private Uri mUri;
	private boolean isLooping;

	private Handler mHandler;
	private MusicSourceType mType;

	private int current = 0;

	private boolean isCountDownRequest = false;

	public void setCountDownRequest(boolean isCountDownRequest) {
		this.isCountDownRequest = isCountDownRequest;
	}

	/**
	 * 每隔1秒回调通知播放进度
	 */
	private Runnable mUpdateTimeTask = new Runnable() {
		public void run() {

			if (mCallback != null) {
				if (mPlayer != null) {
					mCallback.onMusicProgressChanged(current);
					if (isCountDownRequest) {
						current--;
					} else {
						current++;
					}

				}
			}
			mHandler.postDelayed(this, UPDATE_MUSIC_TIME_PERIOD);
		}
	};

	public void setCallback(ALMusicPlayerCallback mCallback) {
		this.mCallback = mCallback;
	}

	/**
	 * 构造方法，播放SD卡中的音频文件
	 * 
	 * @param context
	 * @param path
	 * @param callback
	 * @author Alonso Lee
	 */
	public ALMusicPlayer(Context context, String path,
			ALMusicPlayerCallback callback) {
		// TODO Auto-generated constructor stub
		mType = MusicSourceType.AL_MUSIC_TYPE_STRING_PATH;
		mCallback = callback;
		mContext = context;
		mPath = path;
		mHandler = new Handler();
		build(context, path, mCallback);
	}

	/**
	 * 构造方法，播放资源文件
	 * 
	 * @param context
	 * @param res
	 * @param callback
	 * @author Alonso Lee
	 */
	public ALMusicPlayer(Context context, int res,
			ALMusicPlayerCallback callback) {
		// TODO Auto-generated constructor stub
		mType = MusicSourceType.AL_MUSIC_TYPE_RAW_SOURCE;
		mCallback = callback;
		mContext = context;
		resId = res;
		mHandler = new Handler();
		build(context, resId, mCallback);
	}

	/**
	 * 构造方法，播放Uri指定的音频文件
	 * 
	 * @param context
	 * @param uri
	 * @param callback
	 * @author Alonso Lee
	 */
	public ALMusicPlayer(Context context, Uri uri,
			ALMusicPlayerCallback callback) {
		// TODO Auto-generated constructor stub
		mType = MusicSourceType.AL_MUSIC_TYPE_URI;
		mCallback = callback;
		mContext = context;
		mHandler = new Handler();
		mUri = uri;
		build(context, mUri, mCallback);
	}

	/**
	 * 构造用于播放指定URI的音频文件。
	 * 
	 * @param context
	 * @param uri
	 * @param callback
	 * @return
	 * @author Alonso Lee
	 */
	private MediaPlayer build(Context context, Uri uri,
			ALMusicPlayerCallback callback) {

		// create方法已经执行了prepare，不需要再次执行
		mPlayer = MediaPlayer.create(context, uri);
		if (mPlayer != null) {
			try {
				mPlayer.setLooping(isLooping);

				mPlayer.setOnCompletionListener(new OnCompletionListener() {

					@Override
					public void onCompletion(MediaPlayer mp) {
						// TODO Auto-generated method stub
						if (!isLooping) {
							// 播放已完成
							doStop();

							if (mCallback != null) {
								mCallback.onMusicStop();
							}
						}
					}
				});

				mPlayer.setOnErrorListener(new MediaPlayer.OnErrorListener() {

					@Override
					public boolean onError(MediaPlayer mp, int what, int extra) {
						// TODO Auto-generated method stub
						// 播放失败
						doStop();
						if (mCallback != null) {
							mCallback.onMusicError();
						}
						return false;
					}
				});
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
				if (mCallback != null) {
					mCallback.onMusicError();
				}
			}
		}

		return null;
	}

	/**
	 * 播放内部音频资源
	 * 
	 * @param context
	 * @param res
	 * @param callback
	 * @return
	 * @author Alonso Lee
	 */
	private MediaPlayer build(Context context, int res,
			ALMusicPlayerCallback callback) {

		// create方法已经执行了prepare，不需要再次执行
		mPlayer = MediaPlayer.create(context, res);
		if (mPlayer != null) {
			try {

				mPlayer.setLooping(isLooping);

				mPlayer.setOnCompletionListener(new OnCompletionListener() {

					@Override
					public void onCompletion(MediaPlayer mp) {
						// TODO Auto-generated method stub
						if (!isLooping) {
							// 播放已完成
							doStop();

							if (mCallback != null) {
								mCallback.onMusicStop();
							}
						}
					}
				});

				mPlayer.setOnErrorListener(new MediaPlayer.OnErrorListener() {

					@Override
					public boolean onError(MediaPlayer mp, int what, int extra) {
						// TODO Auto-generated method stub
						// 播放失败
						doStop();
						if (mCallback != null) {
							mCallback.onMusicError();
						}
						return false;
					}
				});
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
				if (mCallback != null) {
					mCallback.onMusicError();
				}
			}
		}

		return null;
	}

	/**
	 * 播放指定路径的音频文件
	 * 
	 * @param context
	 * @param path
	 * @param callback
	 * @return
	 * @author Alonso Lee
	 */
	private MediaPlayer build(Context context, String path,
			ALMusicPlayerCallback callback) {

		mPlayer = new MediaPlayer();

		try {
			mPlayer.setDataSource(path);

			mPlayer.setLooping(isLooping);
			mPlayer.setOnPreparedListener(new OnPreparedListener() {

				@Override
				public void onPrepared(MediaPlayer arg0) {
					// TODO Auto-generated method stub
					isPreparing = false;
				}
			});

			mPlayer.setOnCompletionListener(new OnCompletionListener() {

				@Override
				public void onCompletion(MediaPlayer mp) {
					// TODO Auto-generated method stub
					if (!isLooping) {
						// 播放已完成
						doStop();

						if (mCallback != null) {
							mCallback.onMusicStop();
						}
					}
				}
			});

			mPlayer.setOnErrorListener(new MediaPlayer.OnErrorListener() {

				@Override
				public boolean onError(MediaPlayer mp, int what, int extra) {
					// TODO Auto-generated method stub
					// 播放失败
					doStop();

					if (mCallback != null) {
						mCallback.onMusicError();
					}
					return false;
				}
			});

			// isPreparing = true;
			mPlayer.prepare();
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			if (mCallback != null) {
				mCallback.onMusicError();
			}
		}

		return null;
	}

	@Override
	public void play() {
		// TODO Auto-generated method stub
		doPlay();
	}

	@Override
	public void play(boolean mix) {
		// TODO Auto-generated method stub
		doPlay(mix);
	}

	@Override
	public void resume() {
		// TODO Auto-generated method stub
		doResume();
	}

	@Override
	public boolean isPlaying() {
		// TODO Auto-generated method stub
		if (mPlayer == null) {
			return false;
		}
		if (isPreparing) {
			return false;
		}
		return mPlayer.isPlaying();
	}

	@Override
	public void stop() {
		doStop();
		if (mCallback != null) {
			mCallback.onMusicStop();
		}
	}

	public void stopNoCallback() {
		doStop();
	}

	@Override
	public void pause() {
		// TODO Auto-generated method stub
		doPause();
	}

	@Override
	public int getMusicDuration() {
		// TODO Auto-generated method stub
		if (mPlayer != null) {
			return Math.round(mPlayer.getDuration() / 1000);
		}
		return 0;
	}

	@Override
	public int getCurrentPosition() {
		// TODO Auto-generated method stub
		if (mPlayer != null) {
			return Math.round(mPlayer.getCurrentPosition());
		}
		return 0;
	}

	@Override
	public String getMusicPath() {
		// TODO Auto-generated method stub
		switch (mType) {
		case AL_MUSIC_TYPE_STRING_PATH:
			return mPath;
		case AL_MUSIC_TYPE_URI:
			return mUri.getPath();
		case AL_MUSIC_TYPE_RAW_SOURCE:
		default:
			return null;
		}
	}

	@Override
	public void setLooping(boolean loop) {
		// TODO Auto-generated method stub
		isLooping = loop;
		if (mPlayer != null) {
			mPlayer.setLooping(isLooping);
		}
	}

	@Override
	public boolean isLooping() {
		// TODO Auto-generated method stub
		if (mPlayer != null) {
			return mPlayer.isLooping();
		}
		return false;
	}

	/**
	 * 停止播放
	 * 
	 * @author Alonso Lee
	 */
	private void doStop() {
		if (mPlayer != null) {
			try {
				mPlayer.stop();
			} catch (IllegalStateException e) {
				// this may happen sometimes
			} finally {
				mHandler.removeCallbacks(mUpdateTimeTask);
				mPlayer.reset();
				mPlayer.release();
				mPlayer = null;
			}
		}
	}

	/**
	 * 执行播放功能
	 * 
	 * @author Alonso Lee
	 */
	private void doPlay() {

		// 正在播放
		if (isPlaying()) {
			return;
		}

		// 初始化播放对象
		if (mPlayer == null) {
			switch (mType) {
			case AL_MUSIC_TYPE_RAW_SOURCE:
				build(mContext, resId, mCallback);
				break;
			case AL_MUSIC_TYPE_STRING_PATH:
				build(mContext, mPath, mCallback);
				break;
			case AL_MUSIC_TYPE_URI:
				build(mContext, mUri, mCallback);
				break;
			}
		}

		if (mPlayer != null && !isPreparing) {
			mPlayer.start();
			if (mCallback != null) {
				mCallback.onMusicPlay();
			}
			current = 1;
			if (isCountDownRequest) {
				current = getMusicDuration();
			}
			mHandler.removeCallbacks(mUpdateTimeTask);
			mHandler.post(mUpdateTimeTask);
			// mHandler.postDelayed(mUpdateTimeTask, UPDATE_MUSIC_TIME_PERIOD);
		}
	}

	/**
	 * 执行播放功能
	 * 
	 * @author Alonso Lee
	 */
	private void doPlay(boolean mix) {

		// 初始化播放对象
		if (mPlayer == null) {
			switch (mType) {
			case AL_MUSIC_TYPE_RAW_SOURCE:
				build(mContext, resId, mCallback);
				break;
			case AL_MUSIC_TYPE_STRING_PATH:
				build(mContext, mPath, mCallback);
				break;
			case AL_MUSIC_TYPE_URI:
				build(mContext, mUri, mCallback);
				break;
			}
		}

		if (mPlayer != null && !isPreparing) {
			mPlayer.start();
			// if (mCallback != null) {
			// mCallback.onMusicPlay();
			// }
			// mHandler.removeCallbacks(mUpdateTimeTask);
			// mHandler.postDelayed(mUpdateTimeTask, UPDATE_MUSIC_TIME_PERIOD);
		}
	}

	/**
	 * 暂停音乐播放
	 * 
	 * @author Alonso Lee
	 */
	private void doPause() {
		if (mPlayer != null) {
			if (isPreparing) {
				return;
			}

			if (mPlayer.isPlaying()) {
				mPlayer.pause();
				mHandler.removeCallbacks(mUpdateTimeTask);
				if (mCallback != null)
					mCallback.onMusicPause();
			}
		}
	}

	private void doResume() {
		if (mPlayer != null) {
			if (isPreparing) {
				return;
			}

			if (mPlayer != null && !isPreparing) {
				mPlayer.start();
				if (mCallback != null) {
					mCallback.onMusicPlay();
				}
				mHandler.removeCallbacks(mUpdateTimeTask);
				// mHandler.postDelayed(mUpdateTimeTask,
				// UPDATE_MUSIC_TIME_PERIOD);
				mHandler.post(mUpdateTimeTask);

			}

		}
	}

	private enum MusicSourceType {
		AL_MUSIC_TYPE_STRING_PATH, AL_MUSIC_TYPE_URI, AL_MUSIC_TYPE_RAW_SOURCE,
	}

}
